﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Collections.Generic;
using System.Reflection;

namespace Silverlight.InputCtrl
{
    internal enum DefaultTypeToValidator
    {
        None,
        TextBox,
        PasswordBox
    }

    internal class ValidatorCommon
    {
        private static Thickness InvalidDefaultBorderThicknessTooptip()
        {
            return new Thickness(2);
        }
        
        private static Brush InvalidDefaultForegroundTooptip()
        {
            return new SolidColorBrush(Colors.White);
        }

        private static Brush InvalidDefaultBackgroundTooptip()
        {
            return new SolidColorBrush(Colors.Red);
        }

        private static Brush InvalidDefaultBorderBrushTooptip()
        {
            return new SolidColorBrush(Colors.Red);
        }

        private static Brush InvalidDefaultBorder()
        {
            return new SolidColorBrush(Colors.Red);
        }

        private static Thickness InvalidDefaultBorderThickness()
        {
            return new Thickness(1);
        }

        internal static DefaultTypeToValidator GetTypeElement(FrameworkElement element)
        {
            if (element is TextBox)
            {
                return DefaultTypeToValidator.TextBox;
            }
            else if (element is PasswordBox)
            {
                return DefaultTypeToValidator.PasswordBox;
            }
            return DefaultTypeToValidator.None;
        }

        internal static string GetValueText(FrameworkElement element,string PropertyName)
        {
            if (PropertyName != "")
            {
                PropertyInfo pinfo = element.GetType().GetProperty(PropertyName);
                string result = null;
                if (pinfo != null)
                {
                    var v = pinfo.GetValue(element, null);
                    if (v != null)
                    {
                        result = v.ToString();
                    }
                }
                return result;
            }
            switch (GetTypeElement(element))
            {
                case DefaultTypeToValidator.TextBox:
                    return (element as TextBox).Text;
                case DefaultTypeToValidator.PasswordBox:
                    return (element as PasswordBox).Password;
            }
            return null;
        }

        internal static void addEventLeave(FrameworkElement element)
        {
            if (element is Control)
            {
                ((Control)element).LostFocus += new RoutedEventHandler(Common_LostFocus);
            }
        }

        private static void Common_LostFocus(object sender, RoutedEventArgs e)
        {
            OnValidate(sender);
        }

        internal static void addEventChanged(FrameworkElement element)
        {
            element.KeyUp += new System.Windows.Input.KeyEventHandler(Common_KeyUp);
        }

        static void Common_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
            OnValidate(sender);
        }

        internal static void OnReset(object sender)
        {
            FrameworkElement fe = (FrameworkElement)sender;
            ValidatorCollection cbv = fe.GetValue(ValidatorService.ValidatorsProperty) as ValidatorCollection;
            List<string> Errors = new List<string>();
            if (cbv != null)
            {
                Behaviortrigger bt = fe.GetValue(ValidatorService.behaviorProperty) as Behaviortrigger;

                var elemMsgs = ValidatorManager.FindElementsErrorMessage(fe.Name);

                foreach (var item in elemMsgs)
                {
                    item.ElementMessage.Visibility = Visibility.Collapsed;
                }
                if (bt.BorderIndicator)
                {
                    ((Control)fe).BorderBrush = cbv.ElementBorder;
                    ((Control)fe).BorderThickness = cbv.ElementBorderThickness;
                }
                if (bt.MessageTooltip)
                {
                    ToolTipService.SetToolTip(fe, cbv.ElementTooltip);
                }
            }
        }

        internal static void OnValidate(object sender)
        {
            FrameworkElement fe = (FrameworkElement)sender;
            ValidatorCollection cbv = fe.GetValue(ValidatorService.ValidatorsProperty) as ValidatorCollection;
            List<string> Errors = new List<string>();
            if (cbv != null)
            {
                Behaviortrigger bt = fe.GetValue(ValidatorService.behaviorProperty) as Behaviortrigger;

                var elemMsgs = ValidatorManager.FindElementsErrorMessage(fe.Name);

                foreach (var item in cbv)
                {
                    if (item.Enabled)
                    {
                        if (!item.Validate())
                        {
                            Errors.Add(item.ErrorMessage);
                        }
                    }
                }
                if (Errors.Count != 0)
                {
                    foreach (var item in elemMsgs)
                    {
                        if (item.ErrorMessage.ElementError != "")
                        {
                            FrameworkElement ChildElement = null;
                            if (fe.Name != item.ErrorMessage.ElementError)
                            {
                                ChildElement = item.ElementMessage.FindName(item.ErrorMessage.ElementError) as FrameworkElement;
                            }
                            else
                            {
                                ChildElement = fe;
                            }
                            if (ChildElement is TextBlock)
                            {
                                TextBlock tb = ChildElement as TextBlock;
                                tb.Text = string.Empty;
                                foreach (var err in Errors)
                                {
                                    Run r = new Run();
                                    r.Text = err;
                                    if (item.ErrorMessage.ErrorForeground != null)
                                    {
                                        r.Foreground = item.ErrorMessage.ErrorForeground;
                                    }
                                    if (item.ErrorMessage.ErrorFontFamily != null)
                                    {
                                        r.FontFamily = item.ErrorMessage.ErrorFontFamily;
                                    }
                                    if (item.ErrorMessage.ErrorFontSize > 0)
                                    {
                                        r.FontSize = item.ErrorMessage.ErrorFontSize;
                                    }
                                    if (item.ErrorMessage.ErrorFontWeight != null)
                                    {
                                        r.FontWeight = item .ErrorMessage.ErrorFontWeight;
                                    }
                                    tb.Inlines.Add(r);
                                    tb.Inlines.Add(new LineBreak());
                                }
                            }
                            else if (ChildElement is Panel)
                            {
                                ((Panel)ChildElement).Children.Clear();
                                ((Panel)ChildElement).Children.Add(CreateStackErro(Errors,item));
                            }
                        }
                        item.ElementMessage.Visibility = Visibility.Visible;
                    }

                    if (bt.BorderIndicator)
                    {
                        if (bt.InvalidBorder != null)
                        {
                            ((Control)fe).BorderBrush = bt.InvalidBorder;
                        }
                        else
                        {
                            ((Control)fe).BorderBrush = InvalidDefaultBorder();
                        }
                        if (bt.InvalidBorderThickness != new Thickness())
                        {
                            ((Control)fe).BorderThickness = bt.InvalidBorderThickness;
                        }
                        else
                        {
                            ((Control)fe).BorderThickness = InvalidDefaultBorderThickness();
                        }
                    }
                    if (bt.MessageTooltip)
                    {
                        CreateTooltip(fe, Errors);
                    }

                }
                else
                {
                    foreach (var item in elemMsgs)
                    {
                        item.ElementMessage.Visibility = Visibility.Collapsed;
                    }
                    if (bt.BorderIndicator)
                    {
                        ((Control)fe).BorderBrush = cbv.ElementBorder;
                        ((Control)fe).BorderThickness = cbv.ElementBorderThickness;
                    }
                    if (bt.MessageTooltip)
                    {
                        ToolTipService.SetToolTip(fe, cbv.ElementTooltip);
                    }   
                }
                fe.UpdateLayout();
            }
        }

        private static StackPanel CreateStackErro(List<string> Errors, ErroMessageElementInfo vldmsg)
        {
            StackPanel sp = new StackPanel();
            sp.Orientation = Orientation.Vertical;
            foreach (var item in Errors)
            {
                TextBlock tb = new TextBlock();
                tb.TextWrapping = TextWrapping.Wrap;
                tb.Text = item;
                tb.Margin = new Thickness(5, 2, 5, 2);
                if (vldmsg.ErrorMessage.ErrorBackground != null)
                {
                    sp.Background = vldmsg.ErrorMessage.ErrorBackground;
                }
                if (vldmsg.ErrorMessage.ErrorForeground != null)
                {
                    tb.Foreground = vldmsg.ErrorMessage.ErrorForeground;
                }
                if (vldmsg.ErrorMessage.ErrorFontFamily != null)
                {
                    tb.FontFamily = vldmsg.ErrorMessage.ErrorFontFamily;
                }
                if (vldmsg.ErrorMessage.ErrorFontSize > 0)
                {
                    tb.FontSize = vldmsg.ErrorMessage.ErrorFontSize;
                }
                if (vldmsg.ErrorMessage.ErrorFontWeight != null)
                {
                    tb.FontWeight = vldmsg.ErrorMessage.ErrorFontWeight;
                }
                sp.Children.Add(tb);
            }
            return sp;
        }

        private static void CreateTooltip(FrameworkElement element, List<string> Errors)
        {
            StackPanel sp = new StackPanel();
            sp.Orientation = Orientation.Vertical;
            foreach (var item in Errors)
	        {
                sp.Children.Add(new TextBlock(){ Text= item,  Foreground= InvalidDefaultForegroundTooptip(), Margin = new Thickness(5,2,5,2)});
	        }
            ToolTip tp = new ToolTip();
            tp.Opacity = 0;
            tp.Opened += new RoutedEventHandler(tp_Opened);
            Behaviortrigger bt = element.GetValue(ValidatorService.behaviorProperty) as Behaviortrigger;
            if (bt.TooltipForeground != null)
            {
                tp.SetValue(ToolTip.ForegroundProperty, bt.TooltipForeground);
            }
            else
            {
                tp.SetValue(ToolTip.ForegroundProperty, InvalidDefaultForegroundTooptip());
            }
            if (bt.TooltipBackground != null)
            {
                tp.SetValue(ToolTip.BackgroundProperty, bt.TooltipBackground);
            }
            else
            {
                tp.SetValue(ToolTip.BackgroundProperty, InvalidDefaultBackgroundTooptip());
            }
            if (bt.TooltipBorder != null)
            {
                tp.SetValue(ToolTip.BorderBrushProperty, bt.TooltipBorder);
            }
            else
            {
                tp.SetValue(ToolTip.BorderBrushProperty, InvalidDefaultBorderBrushTooptip());
            }
            if (bt.TooltipBorderThickness != new Thickness())
            {
                tp.SetValue(ToolTip.BorderThicknessProperty, bt.TooltipBorderThickness);
            }
            else
            {
                tp.SetValue(ToolTip.BorderThicknessProperty, InvalidDefaultBorderThicknessTooptip());
            }
            tp.SetValue(ToolTip.ContentProperty, sp);
            ToolTipService.SetToolTip(element, tp);
        }

        private static void tp_Opened(object sender, RoutedEventArgs e)
        {
            Storyboard sb = new Storyboard();
            DoubleAnimation db = new DoubleAnimation();
            db.From = 0;
            db.To = 1; 
            db.Duration = TimeSpan.FromMilliseconds(800);
            sb.Duration = TimeSpan.FromSeconds(800);
            sb.Children.Add(db);
            Storyboard.SetTarget(db,(ToolTip)sender);
            Storyboard.SetTargetProperty(db, new PropertyPath("(Opacity)")); 
            sb.Begin();
        }
    }
}
